package pub.guoxin.oops.manager.handler;

import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import pub.guoxin.oops.common.cache.CacheKeyFormatEnums;
import pub.guoxin.oops.common.cache.CacheService;
import pub.guoxin.oops.common.sms.enums.SmsSignName;
import pub.guoxin.oops.common.sms.enums.SmsTemplate;
import pub.guoxin.oops.common.sms.service.SmsSender;
import pub.guoxin.oops.enums.ComparisonOperator;
import pub.guoxin.oops.manager.vo.AlarmCacheVo;
import pub.guoxin.oops.model.*;
import pub.guoxin.oops.repository.*;
import pub.guoxin.oops.utils.JsonUtils;
import pub.guoxin.oops.utils.ParseKeyword;

import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * 报警信息处理基类
 */
@Slf4j
public abstract class AbstractAlarmInfoHandler {

    /**
     * tow hour
     */
    public static final long TWO_HOUR = 1000 * 60 * 60 * 2;

    @Resource
    protected DataAlarmConfigRepository dataAlarmConfigRepository;
    @Resource
    protected AlarmDisposeRepository alarmDisposeRepository;
    @Autowired
    protected AlarmInfoRepository alarmInfoRepository;
    @Autowired
    protected RealTimeCommunicationRepository realTimeCommunicationRepository;
    @Autowired
    private GroupRepository groupRepository;
    @Autowired
    private UserRepository userRepository;
    @Autowired
    private CacheService cacheService;
    @Autowired
    private SmsSender sender;
    /**
     * 持有下一个处理请求的对象
     */
    private AbstractAlarmInfoHandler successor = null;

    protected boolean isNextHandler() {
        return !Objects.isNull(successor);
    }

    protected AbstractAlarmInfoHandler getSuccessor() {
        return this.successor;
    }

    public void setSuccessor(AbstractAlarmInfoHandler successor) {
        this.successor = successor;
    }

    /**
     * 处理聚餐费用的申请
     *
     * @param communicationData 被处理数据
     * @param alarmInfos  报警信息
     */
    public abstract List<AlarmInfo> handleRequest(CommunicationData communicationData, List<AlarmInfo> alarmInfos);

    protected void communicationSnGreaterThanOrLessThan(AlarmCacheVo result, String communicationSn, String deviceSn, Float value, String fieldName, SmsTemplate smsTemplate, ComparisonOperator comparisonOperator){
        Map<String, String> param = Maps.newHashMap();
        param.put("sn", communicationSn);
        param.put("value", String.valueOf(value));
        greaterThanOrLessThan(result, communicationSn, deviceSn, value, fieldName, smsTemplate, comparisonOperator, param);
    }
    protected void deviceSnGreaterThanOrLessThan(AlarmCacheVo result, String communicationSn, String deviceSn, Float value, String fieldName, SmsTemplate smsTemplate, ComparisonOperator comparisonOperator){
        Map<String, String> param = Maps.newHashMap();
        param.put("sn", deviceSn);
        param.put("value", String.valueOf(value));
        greaterThanOrLessThan(result, communicationSn, deviceSn, value, fieldName, smsTemplate, comparisonOperator, param);
    }

    private void greaterThanOrLessThan(AlarmCacheVo result, String communicationSn, String deviceSn,  Float value, String fieldName, SmsTemplate smsTemplate, ComparisonOperator comparisonOperator, Map<String, String> param){
        // 缓存中是否存在对应报警信息

        if (Objects.nonNull(result)) {
            // 取出报警处理ID与报警时间，将ID与数据共同存入数据库
            String content = ParseKeyword.parse(smsTemplate.getContent(), param);
            saveAlarmInfoResult(result.getAlarmDisposeId(), communicationSn, fieldName, deviceSn, value, content);
            // （当前时间-报警时间）/2小时<=发送短息次数
            if (System.currentTimeMillis() - result.getTimestamp() <= TWO_HOUR) {
                // TODO 发送预警短信
                boolean send = send(communicationSn, param, smsTemplate);
                result.setSendSmsCount(result.getSendSmsCount() + 1);
                putAlarmInfo(communicationSn, deviceSn, comparisonOperator.getValue(), fieldName, result);
            }
            putAlarmInfo(communicationSn, deviceSn, comparisonOperator.getValue(), fieldName, result);
        } else {
            String content = ParseKeyword.parse(smsTemplate.getContent(), param);
            // 创建报警处理
            String alarmDisposeId = saveAlarmDispose(communicationSn, fieldName, deviceSn, value, content);
            // 在缓存中创建报警信息缓存
            result = new AlarmCacheVo();
            result.setAlarmDisposeId(alarmDisposeId);
            result.setSendSmsCount(1L);
            result.setTimestamp(System.currentTimeMillis());
            putAlarmInfo(communicationSn, deviceSn, comparisonOperator.getValue(), fieldName, result);
//                    "通讯模块串号为" + communicationSn + "的剩余电池电量为" + value + "请及时更换电池！"

            saveAlarmInfoResult(alarmDisposeId, communicationSn, fieldName, deviceSn, value, content);
            // TODO 发送预警短信
            boolean send = send(communicationSn, param, smsTemplate);
        }
    }

    /**
     * 数据正常执行如下操作
     * @param result
     * @param communicationSn
     * @param deviceSn
     * @param comparisonOperator
     * @param fieldName
     */
    protected void dataNormal(AlarmCacheVo result, String communicationSn, String deviceSn,ComparisonOperator comparisonOperator, String fieldName) {
        if (Objects.nonNull(result)) {
            long sub = System.currentTimeMillis() - result.getTimestamp();
            if ((TWO_HOUR - sub) >= 0) {
                deleteAlarmInfo(communicationSn, deviceSn, comparisonOperator.getValue(), fieldName);
            }
        }
    }

    /**
     * 创建报警处理
     *
     * @param communicationSn
     * @param fieldName
     * @param deviceSn
     * @param value
     * @param content
     * @return
     */
    protected String saveAlarmDispose(String communicationSn, String fieldName, String deviceSn, Float value, String content){
        RealTimeCommunication realTimeCommunication = getRealTimeCommunication(communicationSn);
        AlarmDispose alarmDispose = new AlarmDispose();
        alarmDispose.setCommunicationSn(communicationSn);
        alarmDispose.setFieldName(fieldName);
        alarmDispose.setDeviceSn(deviceSn);
        alarmDispose.setCompanyId(realTimeCommunication.getCompanyId());
        alarmDispose.setGroupId(realTimeCommunication.getGroupId());
        alarmDispose.setContent(content);
        alarmDispose.setValue(value);
        alarmDispose.init();
        AlarmDispose insert = alarmDisposeRepository.insert(alarmDispose);
        return insert.getId();
    }

    /**
     * 持久化告警数据
     *
     * @param alarmDisposeId  报警处理ID
     * @param communicationSn 通讯模块SN
     * @param fieldName       字段名称
     * @param deviceSn        设备SN
     * @param value           告警字段值
     */
    protected void saveAlarmInfoResult(String alarmDisposeId, String communicationSn, String fieldName, String deviceSn, Float value, String content) {
        RealTimeCommunication realTimeCommunication = getRealTimeCommunication(communicationSn);
        AlarmInfo alarmInfo = new AlarmInfo();
        alarmInfo.setAlarmDisposeId(alarmDisposeId);
        alarmInfo.setCommunicationSn(communicationSn);
        alarmInfo.setFieldName(fieldName);
        alarmInfo.setDeviceSn(deviceSn);
        alarmInfo.setGroupId(realTimeCommunication.getGroupId());
        alarmInfo.setCompanyId(realTimeCommunication.getCompanyId());
        alarmInfo.setContent(content);
        alarmInfo.setValue(value);
        alarmInfo.init();
        alarmInfoRepository.insert(alarmInfo);
    }

    protected boolean send(String communicationSn, Map<String, String> templateParam, SmsTemplate template) {
        RealTimeCommunication rtc = getRealTimeCommunication(communicationSn);
        if (Objects.isNull(rtc)) {
            log.info("未找到对应的RealTimeCommunication！！！");
            return false;
        }
        Group group = groupRepository.findOne(rtc.getCompanyId());
        if (Objects.isNull(group)) {
            log.info("未找到对应的公司Group！！！");
            return false;
        }
        User one = userRepository.findOne(group.getUserId());
        if (Objects.isNull(one)) {
            log.info("未找到对应管理员User！！！");
            return false;
        }
        boolean send = sender.send(one.getMobile(), templateParam, template, SmsSignName.WUWU);
        if (!send) {
            log.info("发送短信失败");
        }
        return true;
    }

    private RealTimeCommunication getRealTimeCommunication(String communicationSn) {
        RealTimeCommunication one = realTimeCommunicationRepository.findOne(communicationSn);
        if (Objects.isNull(one)) {
            throw new CommunicationNotFountException("通讯模块为注册！！！");
        }
        return one;
    }

    protected AlarmInfo saveAlarmInfo(AlarmInfo alarmInfo) {
        return alarmInfoRepository.save(alarmInfo);
    }

    protected void exceptionRecord(List<AlarmInfo> alarmInfos, AlarmInfo alarmInfo) {
        alarmInfos.add(alarmInfo);
    }

//    protected void baseHandle(CommunicationData communicationData){
//        String communicationSn = communicationData.getCommunication().getSn();
//        communicationData.getDeviceDataInfos().forEach(deviceDataInfo -> {
//            String sn = deviceDataInfo.getSn();
//            CacheKeyFormatEnums.ALARM_COMMUNICATION_DVICE.key();
//        });
//    }

    /**
     * 将报警信息压入缓存
     *
     * @param communicationSn    通讯模块SN
     * @param deviceSn           设备SN
     * @param comparisonOperator 操作运算符
     * @param fieldName          字段名称
     */
    protected void putAlarmInfo(String communicationSn, String deviceSn, String comparisonOperator, String fieldName, AlarmCacheVo alarmCacheVo) {
        String key = CacheKeyFormatEnums.ALARM_COMMUNICATION_DVICE.key(communicationSn, deviceSn, fieldName, comparisonOperator);
        String value = JsonUtils.obj2json(alarmCacheVo);
        cacheService.put(key, value, CacheKeyFormatEnums.ALARM_COMMUNICATION_DVICE.getTimeout());
    }

    /**
     * 将报警信息取出
     *
     * @param communicationSn    通讯模块SN
     * @param deviceSn           设备SN
     * @param comparisonOperator 操作运算符
     * @param fieldName          字段名称
     * @return 缓存数据
     */
    protected AlarmCacheVo getAlarmInfo(String communicationSn, String deviceSn, ComparisonOperator comparisonOperator, String fieldName) {
        return cacheService.get(CacheKeyFormatEnums.ALARM_COMMUNICATION_DVICE.key(communicationSn, deviceSn, fieldName, comparisonOperator.getValue()), AlarmCacheVo.class);
    }

    /**
     * 将报警信息取出
     *
     * @param communicationSn    通讯模块SN
     * @param deviceSn           设备SN
     * @param comparisonOperator 操作运算符
     * @param fieldName          字段名称
     */
    protected void deleteAlarmInfo(String communicationSn, String deviceSn, String comparisonOperator, String fieldName) {
        cacheService.del(CacheKeyFormatEnums.ALARM_COMMUNICATION_DVICE.key(communicationSn, deviceSn, fieldName, comparisonOperator));
    }

    /**
     * 报警信息
     *
     * @param communicationSn    通讯模块SN
     * @param deviceSn           设备SN
     * @param comparisonOperator 操作运算符
     * @param fieldName          字段名称
     */
    protected boolean notExists(String communicationSn, String deviceSn, String comparisonOperator, String fieldName) {
        return !cacheService.exists(CacheKeyFormatEnums.ALARM_COMMUNICATION_DVICE.key(communicationSn, deviceSn, fieldName, comparisonOperator));
    }

}
